package sp.whereru;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.Paint.Style;
import android.graphics.Region.Op;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;

public class AreasOverlay extends Overlay {
	private final Map<String, List<GeoPoint>> mAreas;
	private final Paint mPaintFill;
	private final Paint mPaintStroke;
	private static final int ALPHA = 0x50ffffff; // 48 out of 255 transparent
	private static final int[] COLORS =
		{ Color.BLUE, Color.RED, Color.GREEN, Color.MAGENTA, Color.YELLOW, Color.CYAN };
	static {
		for (int i = 0; i < AreasOverlay.COLORS.length; i++) {
			AreasOverlay.COLORS[i] &= AreasOverlay.ALPHA;
		}
	}


	public AreasOverlay(final Map<String, List<GeoPoint>> areaMap) {
		mAreas = areaMap;
		// prepare paints
		mPaintFill = new Paint();
		mPaintFill.setStyle(Paint.Style.FILL);
		mPaintStroke = new Paint(Paint.ANTI_ALIAS_FLAG);
		mPaintStroke.setStyle(Style.STROKE);
		mPaintStroke.setAntiAlias(true);
		mPaintStroke.setStrokeWidth(3);
	}

	@Override
	public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
		super.draw(canvas, mapView, shadow);
		if (shadow) {
			return;
		}
		Projection projection = mapView.getProjection();

		List<Path> areaPaths = getPaths(projection, mAreas);
		drawPaths(canvas, areaPaths);
	}

	private List<Path> getPaths(final Projection projection, final Map<String, List<GeoPoint>> areas) {
		List<Path> areaPaths = new ArrayList<Path>(areas.size());
		for (Map.Entry<String, List<GeoPoint>> entry : areas.entrySet()) {
			List<GeoPoint> sourceList = entry.getValue();
			Path path = new Path();
			path.setFillType(Path.FillType.EVEN_ODD);
			Iterator<GeoPoint> it = sourceList.iterator();
			Point point = nextDrawPoint(projection, it);
			path.moveTo(point.x, point.y);
			while (it.hasNext()) {
				point = nextDrawPoint(projection, it);
				path.lineTo(point.x, point.y);
			}
			path.close();
			areaPaths.add(path);
		}
		return areaPaths;
	}

	/**
	 * Draw with different colors.
	 * Draw strokes first for them to be always visible.
	 * Draw fills next with each removing from the drawable area.
	 */
	private void drawPaths(final Canvas canvas, final List<Path> areaPaths) {
		int currentColorIndex;

		currentColorIndex = 0;
		for (Path path : areaPaths) {
			int currentColor = AreasOverlay.COLORS[currentColorIndex++];
			currentColorIndex %= AreasOverlay.COLORS.length;
			mPaintStroke.setColor(currentColor & 0xff7f7f7f); // make it darker by clearing the high bit
			canvas.drawPath(path, mPaintStroke);
		}
		currentColorIndex = 0;
		for (Path path : areaPaths) {
			int currentColor = AreasOverlay.COLORS[currentColorIndex++];
			currentColorIndex %= AreasOverlay.COLORS.length;
			mPaintFill.setColor(currentColor);
			canvas.drawPath(path, mPaintFill);
			canvas.clipPath(path, Op.DIFFERENCE); // don't allow to draw over each other
		}
	}

	private Point nextDrawPoint(final Projection projection, final Iterator<GeoPoint> it) {
		GeoPoint geo = it.next();
		Point p = new Point();
		projection.toPixels(geo, p);
		return p;
	}	
}
